package com.ConwayLife;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/*
生命游戏是一个无限的，二维正方形的栅格单元网格，每一个单元格有2种状态可能性：活或死的（或者黑和白）。
每个单元格都与其八个相邻的单元交互，这八个单元格是水平、垂直或对角线相邻的单元格。在每个时间步上，都会发生以下转换：
    当前细胞为存活状态时，当周围的存活细胞低于2个时（不包含2个），该细胞变成死亡状态。（模拟生命数量稀少）
    当前细胞为存活状态时，当周围有2个或3个存活细胞时，该细胞保持原样。
    当前细胞为存活状态时，当周围有超过3个存活细胞时，该细胞变成死亡状态。（模拟生命数量过多）
    当前细胞为死亡状态时，当周围有3个存活细胞时，该细胞变成存活状态。（模拟繁殖）

这些将自动机的行为与现实生活进行比较的规则可以归纳为以下内容：
    任何有两个或三个邻居的活细胞都可以存活。
    具有三个活动邻居的任何死细胞都将成为活细胞。
    所有其他活细胞将在下一代死亡。同样，所有其他死细胞仍保持死亡状态。

可以把最初的细胞结构定义为种子，当所有在种子中的细胞同时被以上规则处理后，可以得到第一代细胞图。
按规则继续处理当前的细胞图，可以得到下一代的细胞图，周而复始。

1. 静态模式：方块，面包，蜂巢，大船，小船，花，池塘，航空母舰，独木舟，芒果，鸭子
2. 震荡态模式：信号灯，蟾蜍，红绿灯，烽火，脉冲星，慨影
3. 太空船模式：滑翔机，太空船

*/

//public class ConwayLife extends JFrame implements ActionListener {
public class ConwayLife  {
	
	private volatile int msDemoStep = 200;
	private volatile boolean toStop = false;
	private int steps = 0;
	private int nRow = 50;
	private int nCol = 50;
	private int[][] gameCells1;
	private int[][] gameCells2;
	// 用于判断 is game over
	private int[][] gameCells3;
	private static int seed = 0;
	
	//添加对某个变量的监听，第一个参数是变量名，第二个是变量改变前的值，第二个是变量改变后的值
	private final PropertyChangeSupport propertyChanges = 
			        new PropertyChangeSupport(this);
    private int propertyState = 0;
    
	//----------------------------- -----------------------------------
    public void addPropertyChangeListener(PropertyChangeListener listener) {
    	propertyChanges.addPropertyChangeListener(listener);
    	//System.out.println("addPropertyChangeLister: ");
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
    	propertyChanges.removePropertyChangeListener(listener);
    	//System.out.println("removePropertyChangeLister: ");
    }

    // 当需要通知 Listener 时，执行如下语句
    // propertyChanges.firePropertyChange("ConwayLife", Object oldValue, Object newValue) {

	// 启动线程
	public void startConwayThread() {
		// 生成一个匿名线程 并开始执行
		new Thread() {
			public void run() {
				System.out.println("ConwayLife: getNextGame ...");
				int[][] mat = getNextGame();
				propertyChanges.firePropertyChange("ConwayLife", false, mat);
				waitMS(900);
				waitMS(900);
				// 游戏每一步发送一次
				while(!toStop) {
					// 发送中间结果
					mat = getNextGame();
					propertyChanges.firePropertyChange("ConwayLife", false, mat);
					waitMS(msDemoStep);
					// 将进化状态返回给主程序，oldValue = status
					int status = isGameOver();
					// 1,停止状态
					if (status == 1) {
						// 现场结束
						propertyChanges.firePropertyChange("ConwayLife is over!", false, status);
						waitMS(msDemoStep);
						break;
					}
					// 2,震荡状态
					else if(status == 2) {
						// 现场结束
						propertyChanges.firePropertyChange("ConwayLife is over!", false, status);
						waitMS(msDemoStep);
						break;
					}
					// 0,继续进化
					else {
						; 
					}
				}
			} // end run
		}.start();
	}

    // 设置 show demo step 的值，单位为 ms
    public void resetDemoStep(int ms) {
    	msDemoStep = ms;
    	if (msDemoStep < 50)
    		msDemoStep = 50;
    	if (msDemoStep > 1000)
    		msDemoStep = 1000;
   
    	return; 
    }
    
    public void resetStopFlag(boolean bt) {
    	toStop = bt;
    	return; 
    }

	private void waitMS(int ms) {
		if( ms < 1)
			return;
		try {
			Thread.sleep(ms);
		} 
		catch (Exception e) {
			throw new RuntimeException("waitMS error: Thread.sleep");
		}		
	}
	
	// gameCells[][] = 1, 黑色; gameCells[][] = 0, 白色
	private void clearGame(int[][] gameCells) {
		for(int i=0; i<gameCells.length; i++) {
			for(int j=0; j<gameCells[0].length; j++) {
				gameCells[i][j] = 0;
			}
		}
	}
	
	// deep copy: int[][] game1 -> int[][] game2
	private void copyGame(int[][] game1, int[][] game2) {
		//int len = row*col;
		//System.arraycopy(gameCells1, 0, gameCells2, 0, len);
		for(int i=0; i<game1.length; i++) {
			for(int j=0; j<game1[0].length; j++) {
				game2[i][j] = game1[i][j];
			}
		}
	}

	public ConwayLife() {
		super();
	}
	
	// Customise模式下, 初始产生cells=1 的概率为 1/prob
	public ConwayLife(int seed, int width, int hight) {
		this.nRow = width;
		this.nCol = hight;
		gameCells1 = new int[nRow][nCol];
		gameCells2 = new int[nRow][nCol];
		gameCells3 = new int[nRow][nCol];
		clearGame(gameCells1);
		clearGame(gameCells2);
		clearGame(gameCells3);
		// ConwayLifeSeed.Glider
		if (seed == 1) {			
			//滑翔机 glider
			gameCells1[0][0] = 1; 
			gameCells1[1][1] = 1; 
			gameCells1[2][0] = 1; 
			gameCells1[2][1] = 1; 
			gameCells1[1][2] = 1; 
		}// ConwayLifeSeed.GliderGun
		else if (seed == 2) {
			//滑翔机枪 Gosper glider gun
			gameCells1[5][1] = 1; 
			gameCells1[5][2] = 1; 
			gameCells1[6][1] = 1; 
			gameCells1[6][2] = 1; 
			gameCells1[6][11] = 1; 
			gameCells1[5][12] = 1; 
			gameCells1[6][12] = 1; 
			gameCells1[7][12] = 1; 
			gameCells1[4][13] = 1; 
			gameCells1[5][13] = 1; 
			gameCells1[6][13] = 1;
			gameCells1[7][13] = 1; 
			gameCells1[8][13] = 1; 
			gameCells1[3][14] = 1; 
			gameCells1[4][14] = 1; 
			gameCells1[8][14] = 1;
			gameCells1[9][14] = 1; 
			gameCells1[4][15] = 1; 
			gameCells1[5][15] = 1; 
			gameCells1[6][15] = 1; 
			gameCells1[7][15] = 1;
			gameCells1[8][15] = 1; 
			gameCells1[4][16] = 1; 
			gameCells1[8][16] = 1; 
			gameCells1[5][17] = 1; 
			gameCells1[7][17] = 1;
			gameCells1[6][18] = 1; 
			gameCells1[4][21] = 1; 
			gameCells1[2][22] = 1; 
			gameCells1[3][22] = 1; 
			gameCells1[5][22] = 1;
			gameCells1[6][22] = 1; 
			gameCells1[1][24] = 1; 
			gameCells1[7][24] = 1; 
			gameCells1[1][26] = 1; 
			gameCells1[2][26] = 1;
			gameCells1[4][26] = 1; 
			gameCells1[6][26] = 1; 
			gameCells1[7][26] = 1; 
			gameCells1[3][35] = 1; 
			gameCells1[4][35] = 1;
			gameCells1[3][36] = 1; 
			gameCells1[4][36] = 1; 			
		}//ConwayLifeSeed.Spaceship		
		else if (seed == 3) {
			//飞船 spaceship
			gameCells1[3][nCol - 1] = 1; 
			gameCells1[5][nCol - 1] = 1; 
			gameCells1[2][nCol - 2] = 1; 
			gameCells1[2][nCol - 3] = 1; 
			gameCells1[2][nCol - 4] = 1; 
			gameCells1[2][nCol - 5] = 1; 
			gameCells1[3][nCol - 5] = 1; 
			gameCells1[4][nCol - 5] = 1; 
			gameCells1[5][nCol - 4] = 1; 			
		}//ConwayLifeSeed.Flower
		else if (seed == 4) {
			//烟花 flower
			gameCells1[4][4] = 1; 
			gameCells1[3][4] = 1; 
			gameCells1[5][4] = 1; 
			gameCells1[4][5] = 1; 
			gameCells1[4][3] = 1; 
		}//ConwayLifeSeed.Butterfly
		else if (seed == 5) {
			//蝴蝶 butterfly
			gameCells1[4][4] = 1; 
			gameCells1[5][4] = 1; 
			gameCells1[6][4] = 1;
			gameCells1[4][5] = 1; 
			gameCells1[5][5] = 1; 
			gameCells1[6][5] = 1; 
			gameCells1[5][6] = 1; 
			gameCells1[2][8] = 1; 
			gameCells1[4][8] = 1;
			gameCells1[6][8] = 1; 
			gameCells1[8][8] = 1; 
			gameCells1[1][9] = 1; 
			gameCells1[9][9] = 1; 
			gameCells1[1][10] = 1; 
			gameCells1[9][10] = 1; 
			gameCells1[1][11] = 1; 
			gameCells1[9][11] = 1; 
			gameCells1[4][11] = 1; 
			gameCells1[6][11] = 1; 
			gameCells1[1][12] = 1;
			gameCells1[2][12] = 1; 
			gameCells1[3][12] = 1; 
			gameCells1[7][12] = 1; 
			gameCells1[8][12] = 1; 
			gameCells1[9][12] = 1; 
			
		}//ConwayLifeSeed.Phoenix
		else if (seed == 6) {
			//凤凰1号 phoenix 1
			gameCells1[1][4] = 1; 
			gameCells1[2][4] = 1; 
			gameCells1[2][6] = 1;
			gameCells1[3][2] = 1; 
			gameCells1[5][1] = 1; 
			gameCells1[5][2] = 1; 
			gameCells1[7][3] = 1; 
			gameCells1[7][5] = 1; 
			gameCells1[8][5] = 1;
			gameCells1[4][7] = 1; 
			gameCells1[4][8] = 1; 
			gameCells1[6][7] = 1;
			
		}
		else if (seed == 7) {
			// random sparse
			customiseGame(10);
		}
		else if (seed == 8) {
			// random normal
			customiseGame(6);
		}
		else if (seed == 9) {
			// random dense
			customiseGame(3);
		}
		else {
			;;;
		}
	}

	// 自定义初始模式, gameCells1[][]按照概率 1/prob 填充
	private void customiseGame(int prob) {
		int len = nRow*nCol;
		Random random = new Random();
		for (int i = 0; i < nRow; i++) {
			for (int j = 0; j < nCol; j++) {
				// 概率 1/prob
				if (random.nextInt(prob) == 1) {
					gameCells1[i][j] = 1;
				}
			}
		}
	}

	// 检查一个 cell 的8个邻居中有多少活着的cell
	// 基于 gameCells1[][] 进行计算
	private int getEighbourAlives(int x, int y) {
		int nbAlive = 0;
		int x1, y1;
		for (int i=-1; i<2; i++) {
			for (int j=-1; j<2; j++) {
				x1 = x + i;
				y1 = y + j;
				if (x1==x && y1==y) {
					continue;
				}
				// 不循环：x1<0 || y1<0 || x1>row-1 || y1>col-1
//				if (x1<0 || y1<0 || x1>row-1 || y1>col-1) {
//					continue;
//				}
				// 设置循环：x1<0 || y1<0 || x1>row-1 || y1>col-1
				if (x1 < 0)
					x1 = nRow-1;
				if (y1 < 0)
					y1 = nCol - 1;
				if (x1 > nRow-1)
					x1 = 0;
				if (y1 > nCol-1)
					y1 = 0;
				// 正常的位置
				if (gameCells2[x1][y1] == 1)
					nbAlive++;
			}
		}
		
		return nbAlive;
	}
	
	/**
	 每一个单元格有2种状态可能性：活或死的, 每个单元格有八个相邻的单元。在每个时间步上，都会发生以下转换：
	 1.当前细胞为存活状态时，当周围的存活细胞低于2个时（不包含2个），该细胞变成死亡状态。（模拟生命数量稀少）
	 2.当前细胞为存活状态时，当周围有2个或3个存活细胞时，该细胞保持原样。
	 3.当前细胞为存活状态时，当周围有超过3个存活细胞时，该细胞变成死亡状态。（模拟生命数量过多）
	 4.当前细胞为死亡状态时，当周围有3个存活细胞时，该细胞变成存活状态。（模拟繁殖）
	*/    
	// gameCells2 --> gameCells3
	private void generateNextGame() {
		clearGame(gameCells3);
		// 每一个单元格有2种状态可能性：活或死的
		for (int i = 0; i < nRow; i++) {
			for (int j = 0; j < nCol; j++) {
				int nbCells = getEighbourAlives(i, j);
				// debug
//				if (i < 6 && j < 6 && nbCells>0)
//					System.out.println("["+i+"]["+j+"]:" + nbCells);
				
				// 当前细胞为存活状态时
				if (gameCells2[i][j] == 1) {
					// 当周围的存活细胞低于2个时（不包含2个），该细胞变成死亡状态
					if (nbCells < 2)
						gameCells3[i][j] = 0;
					// 当周围有2个或3个存活细胞时，该细胞保持原样
					if (nbCells == 2 || nbCells == 3)
						gameCells3[i][j] = gameCells2[i][j];
					// 当周围有超过3个存活细胞时，该细胞变成死亡状态
					if (nbCells > 3)
						gameCells3[i][j] = 0;
				}
				// 当前细胞为死亡状态时
				else {
					// 当周围有3个存活细胞时，该细胞变成存活状态
					if (nbCells == 3)
						gameCells3[i][j] = 1;
				}
			}
		}
		//System.out.println("");
	}

	// 提取游戏下一局，分3种情况处理
	public int[][] getNextGame() {
		// 进行到了第几步
		if (steps < 1) {
			clearGame(gameCells2);
			clearGame(gameCells3);
			steps++;
			return gameCells1;
		}
		// 
		else if (steps == 1) {
			copyGame(gameCells1, gameCells2);
			// gameCells2 --> gameCells3
			generateNextGame();
			steps++;
			return gameCells3;
		}
		else { // (steps > 1) 
			copyGame(gameCells2, gameCells1);	
			copyGame(gameCells3, gameCells2);	
			generateNextGame();
			steps++;
			return gameCells3;
		}
	}
	
	// 如果棋局不变，或者震荡，则 game over; 1,停止状态；2,震荡状态; 0,继续进化
	// gameCells3 == gameCells1 或者 gameCells3 == gameCells2, game over is true  
	public int isGameOver() {	
		if (steps < 9)
			return 0;
		boolean bt1 = isEqualGame(gameCells3, gameCells1);
		boolean bt2 = isEqualGame(gameCells3, gameCells2);
		if (bt1)
			return 2;
		else if(bt2)
			return 1;
		else
			return 0;
	}
	
	// 如果两局相同，返回 true
	private boolean isEqualGame(int[][] game1, int[][] game2) {
		for (int i = 0; i < nRow; i++) {
			for (int j = 0; j < nCol; j++) {
				if (game1[i][j] != game2[i][j])
					return false;
			}
		}
		return true;
	}
	
}
